package cn.vonce.validator.helper;

import cn.vonce.validator.annotation.Validate;
import cn.vonce.validator.model.BeanResult;
import cn.vonce.validator.model.FieldTarget;
import cn.vonce.validator.model.FieldResult;
import cn.vonce.validator.utils.ValidatorUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;

/**
 * 校验字段助手
 *
 * @author Jovi
 * @version 1.0
 * @email imjovi@qq.com
 * @date 2017年4月20日下午6:48:08
 */
public class ValidatorHelper {

    private final static Logger logger = Logger.getLogger(ValidatorHelper.class.getName());

    /**
     * 校验bean
     *
     * @param beanObject bean对象
     * @param group      分组
     * @param interrupt  校验字段遇到错误是否中断不再继续校验(bean模式下生效)
     * @return
     * @author Jovi
     * @date 2018年1月17日下午7:33:27
     */
    public static BeanResult validBean(Object beanObject, String group, boolean interrupt) {
        if (beanObject == null) {
            return new BeanResult("bean" + ValidatorUtil.getNullError());
        }
        List<Field> fields = getBeanAllField(beanObject.getClass());
        List<FieldResult> fieldResultList = new ArrayList<>();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                List<FieldResult> validFieldResultList = valid(field.getAnnotations(), field.getName(), field.get(beanObject), beanObject, group, interrupt);
                if (!validFieldResultList.isEmpty()) {
                    fieldResultList.addAll(validFieldResultList);
                    if (interrupt) {
                        break;
                    }
                }
            } catch (SecurityException | IllegalAccessException | IllegalArgumentException e) {
                logger.warning(e.getMessage());
                return new BeanResult("SecurityException" + e.getMessage());
            }
        }
        if (!fieldResultList.isEmpty()) {
            return new BeanResult("校验存在" + fieldResultList.size() + "条错误", fieldResultList);
        }
        return new BeanResult(true, "校验通过");
    }

    /**
     * 校验单个字段或参数
     *
     * @param annotations bean字段或方法参数注解
     * @param fieldValue  bean字段或方法参数名称
     * @param fieldValue  字段或参数字
     * @param beanObject  bean对象
     * @param group       分组
     * @param interrupt   校验字段遇到错误是否中断不再继续校验(bean模式下生效)
     * @return
     * @author Jovi
     * @date 2018年1月17日下午7:32:06
     */
    public static List<FieldResult> valid(Annotation[] annotations, String fieldName, Object fieldValue, Object beanObject, String group, boolean interrupt) {
        // 消息提示列表
        List<FieldResult> fieldResultList = new ArrayList<>();
        FieldTarget fieldTarget = null;
        try {
            for (Annotation annotation : annotations) {
                Class<? extends Annotation> classType = annotation.annotationType();
                // 判断此注解是否为遵循校验规范的注解
                Validate validate = classType.getAnnotation(Validate.class);
                if (validate == null) {
                    continue;
                }
                String annName = (String) classType.getMethod("name").invoke(annotation);
                String annTip = (String) classType.getMethod("tip").invoke(annotation);
                String[] annGroup = (String[]) classType.getMethod("group").invoke(annotation);
                boolean isMust = false;
                for (String string : annGroup) {
                    // 如果该分组需要校验
                    if (string.equals(group)) {
                        isMust = true;
                        break;
                    }
                }
                if (isMust) {
                    fieldTarget = new FieldTarget();
                    fieldTarget.setName(ValidatorUtil.getFieldName(fieldName, annName));
                    fieldTarget.setTips(annTip);
                    fieldTarget.setValue(fieldValue);
                    fieldTarget.setBean(beanObject);
                    Method method = validate.type().getMethod("handle", Annotation.class, FieldTarget.class);
                    FieldResult fieldResult = (FieldResult) method.invoke(validate.type().newInstance(), annotation, fieldTarget);
                    if (fieldResult != null && !fieldResult.getPass()) {
                        fieldResultList.add(fieldResult);
                        if (interrupt) {
                            break;
                        }
                    }
                }
            }
        } catch (SecurityException e) {
            logger.warning(e.getMessage());
            fieldResultList.add(new FieldResult("[" + fieldTarget.getName() + "]", "出现异常", "SecurityException：" + e.getMessage()));
            return fieldResultList;
        } catch (IllegalAccessException e) {
            logger.warning(e.getMessage());
            fieldResultList.add(new FieldResult("[" + fieldTarget.getName() + "]", "出现异常", "IllegalAccessException：" + e.getMessage()));
            return fieldResultList;
        } catch (IllegalArgumentException e) {
            logger.warning(e.getMessage());
            fieldResultList.add(new FieldResult("[" + fieldTarget.getName() + "]", "出现异常", "IllegalArgumentException：" + e.getMessage()));
            return fieldResultList;
        } catch (InvocationTargetException e) {
            logger.warning(e.getMessage());
            fieldResultList.add(new FieldResult("[" + fieldTarget.getName() + "]", "出现异常", "InvocationTargetException：" + e.getMessage()));
            return fieldResultList;
        } catch (NoSuchMethodException e) {
            logger.warning(e.getMessage());
            fieldResultList.add(new FieldResult("[" + fieldTarget.getName() + "]", "出现异常", "NoSuchMethodException：" + e.getMessage()));
            return fieldResultList;
        } catch (InstantiationException e) {
            logger.warning(e.getMessage());
            fieldResultList.add(new FieldResult("[" + fieldTarget.getName() + "]", "出现异常", "InstantiationException：" + e.getMessage()));
            return fieldResultList;
        }
        return fieldResultList;
    }

    /**
     * Parameter与Field 通用的根据注解类型获取注解方法
     *
     * @param annotations
     * @param annotationClass
     * @return
     * @author Jovi
     * @date 2017年4月20日下午23:15:22
     */
    public static <T extends Annotation> T getAnnotation(Annotation[] annotations, Class<T> annotationClass) {
        T t = null;
        for (Annotation annotation : annotations) {
            if (annotation.annotationType().getName().equals(annotationClass.getName())) {
                t = annotationClass.cast(annotation);
            }
        }
        return t;
    }

    /**
     * 获取字段类型
     *
     * @param typeName
     * @return
     * @author Jovi
     * @date 2017年6月22日下午7:08:13
     */
    public static WhatType whatType(String typeName) {
        WhatType whatType = null;
        switch (typeName) {
            case "String":
            case "Char":
                whatType = WhatType.STRING_TYPE;
                break;
            case "Boolean":
                whatType = whatType.BOOL_TYPE;
                break;
            case "byte":
            case "Byte":
            case "short":
            case "Short":
            case "int":
            case "Integer":
            case "long":
            case "Long":
            case "float":
            case "Float":
            case "double":
            case "Double":
                whatType = WhatType.VALUE_TYPE;
                break;
            case "Date":
                whatType = WhatType.DATE_TYPE;
                break;
            default:
                whatType = WhatType.OTHER_TYPE;
        }
        return whatType;
    }

    /**
     * 获取该bean所有字段（包括父类）
     *
     * @param clazz
     * @return
     */
    public static List<Field> getBeanAllField(Class<?> clazz) {
        if (clazz == null) {
            return Collections.emptyList();
        }
        List<Field> fieldList = new ArrayList<>();
        Class<?> superClass = clazz.getSuperclass();
        do {
            if (superClass != null && superClass != java.lang.Object.class) {
                fieldList.addAll(Arrays.asList(superClass.getDeclaredFields()));
                superClass = superClass.getSuperclass();
            }
            if (superClass != null && superClass == java.lang.Object.class) {
                break;
            }
        } while (superClass != null && superClass != java.lang.Object.class);
        fieldList.addAll(Arrays.asList(clazz.getDeclaredFields()));
        return fieldList;
    }

}
